package model.inventory;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;

import model.Container;
import model.Player;
import model.Settings;
import model.contents.Content;
import model.contents.ContentType;
import model.contents.TextContent;
import model.inventory.InventoryDefinition.BoxType;
import util.LoggingUtils;
import util.PlayerUtilities;

public class InventoryPlayer {

	private static InventoryPlayer _instance;

	public Map<String, InventoryItem> inventoryItems;
	public InventoryDefinition definition;
	public int numberOfRecordsPlayed = 0;
	private int position = 0;

	public List<InventoryRecord> inventoryRecords;

	private String[] keys;

	public static InventoryPlayer getInstance() {
		if (_instance == null) {
			// load inventory player from xml file if the data file exists.
			File inventoryFile = new File(Settings.INVENTORY_XML);
			if (inventoryFile.exists()) {
				Object obj = PlayerUtilities.getObjectFromXMLFile(Settings.INVENTORY_XML);
				if (obj instanceof InventoryPlayer) {
					_instance = (InventoryPlayer) obj;
					_instance.definition = InventoryDefinition.getInstance();
					return _instance;
				}
			}
			_instance = new InventoryPlayer();
			_instance.definition = InventoryDefinition.getInstance();
		}
		return _instance;
	}

	public void saveToXML() {
		System.out.println("saving inventory definition to xml.");
		this.definition.saveToXML();
		System.out.println("saving inventory to xml.");
		PlayerUtilities.saveObjectToXMLFile(Settings.INVENTORY_XML, this);
	}

	public void removeInventoryByVehicleID(List<String> vehicleIDs) {
		for(String vihecleID : vehicleIDs) {
			this.inventoryItems.remove(vihecleID);
		}
		this.generateSortedInventoryItemKeys();
		this.createInventoryRecords();
	}
	
	public void update() {
		this.loadInventoryDefinition();
		this.loadInventorySettings();
		this.createInventoryRecords();
	}

	private InventoryPlayer() {
		this.inventoryItems = new HashMap<String, InventoryItem>();
		this.inventoryRecords = new ArrayList<InventoryRecord>();
		this.keys = new String[0];
		update();
	}

	private void loadInventoryDefinition() {
		InventoryDefinitionBuilder builder = new InventoryDefinitionBuilder();
		this.definition = builder.buildFromCSV();
		new File(Settings.INVENTORY_DEF_CSV).delete();
	}

	private void loadInventorySettings() {
		Map<String, InventoryItem> inventoryMapFromCSV = InventoryItem.getInventoryMapFromCSV(Settings.INVENTORY_CSV);
		updateInventoryItemsWithNewData(inventoryMapFromCSV);
	}

	private void updateInventoryItemsWithNewData(Map<String, InventoryItem> newDataMap) {
		for (String key : newDataMap.keySet()) {
			this.inventoryItems.put(key, newDataMap.get(key));
		}
	}

	public void resetInventory() {
		inventoryItems = new HashMap<String, InventoryItem>();
		this.inventoryRecords = new ArrayList<InventoryRecord>();
	}
	
	public void resetDefinition() {
		definition.reset();
	}
	
	public void resetInventoryPlayer() {
		this.resetInventory();
		this.resetDefinition();
	}

	public void play() {
		System.out.println("this.inventoryRecords.size() = "+this.inventoryRecords.size());
		this.generateSortedInventoryItemKeys();
		this.createInventoryRecords();
		if (getNumRecords() == 0) {
			return;
		}
		while (this.numberOfRecordsPlayed < this.getBatchSize()) {
			if (this.getPosition() >= getNumRecords()) {
				this.setPosition(0);
			}
			// System.out.println("Playing inventory record: " +
			// this.getPosition());
			this.inventoryRecords.get(getPosition()).play();
			this.setPosition(this.getPosition() + 1);
			this.numberOfRecordsPlayed++;
		}

		this.numberOfRecordsPlayed = 0;
	}

	public int getNumRecords() {
		return this.inventoryRecords.size();
	}

	public String[] getInventoryItemsKeys() {
		if (this.keys == null) {
			this.generateSortedInventoryItemKeys();
		}
		return this.keys;
	}

	private void generateSortedInventoryItemKeys() {
		String[] keys = this.inventoryItems.keySet().toArray(new String[] {});
		Arrays.sort(keys);
		this.keys = keys;
	}

	public void createInventoryRecords() {
		// find the containers
		System.out.println("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
		this.inventoryRecords.clear();
		List<Container> containers = new ArrayList<Container>();
		// String[] fieldNames = definition.getFields();
		// System.out.println(Arrays.toString(fieldNames));
		Integer[] containerIDs = definition.getContainerIds();
		
		for (Integer containerID : containerIDs) {
			Container cont = Player.getInstance().getContainer(containerID);
			containers.add(cont);
			//System.out.println(cont);
		}
		
		for (String inventoryKey : this.keys) {
			// build container to content mapping
			InventoryItem item = this.inventoryItems.get(inventoryKey);
			Map<Container, Content> map = new HashMap<Container, Content>();
			// create mapping
			List<Content> imageContents = new ArrayList<Content>();
			for (Integer containerID : containerIDs) {
				String fieldName = definition.getFieldName(containerID);
				try {
					Container c = this.getContainer(containerID);

					if (c == null) {
						//System.out.println("cannot find container with id: " + containerID + ", for inventory field: "
							//	+ fieldName);
						continue;
					}
					
					
					Content content = null;				
					if (definition.getContentType(containerID) == ContentType.TEXT) {
						TextContent txtContent = new TextContent(item.get(fieldName));
						txtContent.setFormat(definition.getTextFormat(fieldName));
						content = txtContent;
					} else if (definition.getContentType(containerID) == ContentType.IMAGE) {
						
						if (item.get(fieldName) != null) {
							int contentID = Integer.parseInt(item.get(fieldName));
							content = Player.getInstance().getContent(contentID);
							
							if(fieldName.contains("co_agent_id"))
							{
								//System.out.println("co agent id = "+fieldName 	+", contentid = "+contentID+", content = "+content.getLocalPath());
							}
							
							
							if (this.definition.getBoxType() == BoxType.REALESTATEBOX && fieldName.contains("picture")) {
								imageContents.add(content);
							} else if(this.definition.getBoxType()==BoxType.AUTOBOX){
								imageContents.add(content);
							}
						}
						
					} else {
						System.out.println("can't play content type: " + definition.getContentType(containerID));
					}
					//System.out.println("One cycle");
					if(content != null)
						map.put(c, content);
				} catch (NumberFormatException ex) {
					System.out.println(fieldName + " " + item.get(fieldName));
					ex.printStackTrace();
					
					String classMethod = "model.inventory .createInventoryRecords()";
					LoggingUtils.logStart(classMethod);
					LoggingUtils.log(Level.SEVERE,ex.getMessage(),ex);
				}
				catch(NullPointerException nu)
				{
					String classMethod = "model.inventory .createInventoryRecords()";
					LoggingUtils.logStart(classMethod);
					LoggingUtils.log(Level.SEVERE,nu.getMessage(),nu);
				}
			}
			
			AutoboxInventoryRecord rec = new AutoboxInventoryRecord(map);
			
			rec.setItem(item);
			
			InventoryRotator rotator = new InventoryRotator(Player.getInstance().getContainer(this.definition.getMainImageContainerId()),
					imageContents);
			
			InventoryTable table = null;
			if (this.definition.getBoxType().equals(BoxType.AUTOBOX)) {
				table = new InventoryTable(this.definition.getTableDefinition(), ContentType.TABLE);
			} else {
				table = new InventoryTable(this.definition.getTableDefinition(), ContentType.REALESTATE_LISTING);
			}
			rec.setRotator(rotator);
			rec.setTable(table);
			rec.setImagePauseTime(definition.getGlobalImagePauseTime());
			this.inventoryRecords.add(rec);
		}
	}

	public int getBatchSize() {
		return this.definition.getNumberOfRecordsToPlayPerCycle();
	}

	public int getPosition() {
		return position;
	}

	public void setPosition(int position) {
		this.position = position;
	}

	public InventoryItem getItem(String key) {
		return this.inventoryItems.get(key);
	}
	
	public Container getContainer(int id) {
		return Player.getInstance().getContainer(id);
	}

	public void removeAllInventory() {
		this.inventoryItems.clear();
	}
}
